package com.acmen.easyapi.strategy.impl;

import com.acmen.easyapi.strategy.ResParamStrategy;
import com.acmen.easyapi.annotation.Param;
import com.acmen.easyapi.annotation.ResParam;
import com.acmen.easyapi.util.ClassUtil;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * @author acmen
 * 策略模式
 */
@Component
public class ResParamStrategyImpl implements ResParamStrategy,ApplicationContextAware {
    private Map<Field, ResParam>  resParams = new HashMap<>();
    private Map<Field, Param>  params = new HashMap<>();

    public ResParam getResParam(Class clazz,Field field){
        String getter = ClassUtil.getGetter(field);
        Method getterMethod =  ClassUtil.getDeclaredMethod(clazz,getter);
        if(getterMethod != null){
            ResParam resParam = getterMethod.getAnnotation(ResParam.class);
            if (resParam != null) {
                return resParam;
            }
        }
        ResParam resParam = ClassUtil.getAnnotation(field, ResParam.class);
        if(resParam != null){
            return resParam;
        }
        for(Map.Entry<Field, ResParam> entry : resParams.entrySet()){
            Field f = entry.getKey();
            if(f.getName().equals(field.getName())
                    &&(f.getType().isAssignableFrom(field.getType())||field.getType().isAssignableFrom(f.getType()))){
                return entry.getValue();
            }
        }
        return null;
    }

    @Override
    public Param getParam(Class clazz,Field field) {
        String getter = ClassUtil.getGetter(field);
        try {
            Method getterMethod = clazz.getDeclaredMethod(getter);
            Param param = getterMethod.getAnnotation(Param.class);
            if (param != null) {
                return param;
            }
        } catch (NoSuchMethodException e) {
           // e.printStackTrace();
        }
        Param param = ClassUtil.getAnnotation(field, Param.class);
        if(param != null){
            return param;
        }
        for(Map.Entry<Field, Param> entry : params.entrySet()){
            Field f = entry.getKey();
            if(f.getName().equals(field.getName())
                    &&(f.getType().isAssignableFrom(field.getType())||field.getType().isAssignableFrom(f.getType()))){
                return entry.getValue();
            }
        }
        return null;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        Map<String, ResParamStrategyImpl> factories = applicationContext.getBeansOfType(ResParamStrategyImpl.class);
        factories.forEach((k,fac)->{
            Field[] files = fac.getClass().getDeclaredFields();
            for(Field field : files){
                ResParam resParam = field.getAnnotation(ResParam.class);
                if(resParam != null){
                    resParams.put(field,resParam);
                }
                Param param = ClassUtil.getAnnotation(field, Param.class);
                if(param !=null){
                    params.put(field,param);
                }
            }
        });
    }
}
